/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package etherblocks.engine.network;

import java.util.LinkedList;
import com.jme3.network.ConnectionListener;
import com.jme3.network.Filters;
import com.jme3.network.HostedConnection;
import com.jme3.network.Message;
import com.jme3.network.MessageConnection;
import com.jme3.network.MessageListener;
import com.jme3.network.Network;
import com.jme3.network.Server;
import etherblocks.engine.exceptions.*;
import etherblocks.engine.network.messages.*;

/**
 *
 * @author Carl
 */
public class NetworkServer extends NetworkClient{
    
    public NetworkServer(int port) throws ServerCreationException{
        createServer(port);
    }
    private Server server;
    private GameServer gameServer;

    private void createServer(int port) throws ServerCreationException{
        try{
            server = Network.createServer(port);
            server.start();
            addMessageListeners();
        }catch(Exception ex){
            throw new ServerCreationException(port);
        }
    }
    
    private void addMessageListeners(){
        server.addConnectionListener(new ConnectionListener(){

            public void connectionAdded(Server server, HostedConnection connection){
                onMessageReceived(connection, new Message_ClientConnection(true));
            }

            public void connectionRemoved(Server server, HostedConnection connection){
                onMessageReceived(connection, new Message_ClientConnection(false));
            }
        });
        server.addMessageListener(new MessageListener<MessageConnection>(){

            public void messageReceived(MessageConnection source, Message message){
                onMessageReceived(source, message);
            }
        });
    }

    @Override
    public void sendMessage(Message message){
        onMessageReceived(null, message);
        broadcastMessage(message);
    }

    @Override
    public void onMessageReceived(MessageConnection source, Message message){
        super.onMessageReceived(source, message);
        int clientID = getMessageSourceID(source);
        if(message instanceof NetworkMessage){
            NetworkMessage networkMessage = (NetworkMessage) message;
            if(gameServer != null){
                MessageResponse messageResponse = gameServer.getMessageResponse(clientID, networkMessage);
                LinkedList<Message> answerMessages = messageResponse.getAnswerMessages();
                for(int i=0;i<answerMessages.size();i++){
                    sendMessageToClient(source, answerMessages.get(i));
                }
                LinkedList<Message> broadcastMessages = messageResponse.getBroadcastMessages();
                for(int i=0;i<broadcastMessages.size();i++){
                    sendMessage(broadcastMessages.get(i));
                }
            }
            if((source != null) && networkMessage.isBroadcastRequired()){
                broadcastMessage(message);
            }
        }
    }
    
    public int getMessageSourceID(MessageConnection source){
        if(source != null){
            if(source instanceof HostedConnection){
                HostedConnection connection = (HostedConnection) source;
                return connection.getId();
            }
        }
        return -1;
    }
    
    public void sendMessageToClient(int clientID, Message message){
        HostedConnection client = ((clientID == -1)?null:server.getConnection(clientID));
        sendMessageToClient(client, message);
    }
    
    private void sendMessageToClient(MessageConnection client, Message message){
        if(client == null){
            onMessageReceived(null, message);
        }
        else{
            server.broadcast(Filters.equalTo(client), message);
        }
    }
    
    private void broadcastMessage(Message message){
        server.broadcast(message);
    }

    @Override
    public int getID(){
        return -1;
    }

    @Override
    public void disconnect(){
        super.disconnect();
        server.close();
    }

    public GameServer getGameServer(){
        return gameServer;
    }

    public void setGameServer(GameServer gameServer){
        this.gameServer = gameServer;
        sendMessage(new Message_ClientConnection(true));
    }
}
